# ================= Logging =================
$logDir  = "C:\ProgramData\FileWaveRename"
$logFile = Join-Path $logDir "rename.log"
if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null }

function Write-Log {
    param([string]$Message, [string]$Level = "INFO")
    Add-Content -Path $logFile -Value ("{0} [{1}] {2}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $Level, $Message)
}

Write-Log "===== Script start ====="

# Remove leftover rename.ps1 from the old version (it contains a plaintext password)
if ($PSScriptRoot) {
    $old = Join-Path $PSScriptRoot "rename.ps1"
    if (Test-Path $old) { Remove-Item $old -Force; Write-Log "Removed leftover $old" "WARN" }
}

# ================= Context =================
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$isAdmin  = ([Security.Principal.WindowsPrincipal]$identity).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
Write-Log "Running as: $($identity.Name) | SYSTEM: $($identity.IsSystem) | Admin/elevated: $isAdmin"
Write-Log "64-bit process: $([Environment]::Is64BitProcess) | PS version: $($PSVersionTable.PSVersion)"

if (-not $isAdmin) {
    Write-Log "Not running elevated. Rename-Computer will fail with access denied. Configure the FileWave fileset to run as SYSTEM/admin." "ERROR"
    exit 6
}

$cs           = Get-CimInstance Win32_ComputerSystem
$partOfDomain = $cs.PartOfDomain
$domainName   = $cs.Domain
Write-Log "Domain joined: $partOfDomain | Domain: $domainName"

# ================= Read FileWave name (both registry views) =================
$valueName    = "fwUser"
$fwClientName = $null
foreach ($view in @([Microsoft.Win32.RegistryView]::Registry32, [Microsoft.Win32.RegistryView]::Registry64)) {
    try {
        $base = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $view)
        $key  = $base.OpenSubKey("SOFTWARE\FileWave\WinClient")
        if ($null -eq $key) { $key = $base.OpenSubKey("SOFTWARE\WOW6432Node\FileWave\WinClient") }
        if ($null -eq $key) { Write-Log "FileWave key not found in $view view" "WARN"; continue }
        $val = $key.GetValue($valueName)
        Write-Log "Found key in $view view. $valueName = '$val'"
        if ($val) { $fwClientName = "$val".Trim(); break }
    } catch {
        Write-Log "Registry read failed in $view view: $_" "ERROR"
    }
}
if (-not $fwClientName) { Write-Log "Could not read '$valueName'." "ERROR"; exit 1 }

# ================= Validate name =================
if ($fwClientName.Length -gt 15 -or $fwClientName -match '[\\/:*?"<>|,~!@#$%^&''(){}_ .]' -or $fwClientName -match '^\d+$') {
    Write-Log "'$fwClientName' is not a valid computer name (max 15 chars, no spaces/special chars/dots, not all digits)." "ERROR"
    exit 4
}

# ================= Compare active + pending name =================
$activeName  = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName").ComputerName
$pendingName = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName").ComputerName
Write-Log "Active: $activeName | Pending: $pendingName | Desired: $fwClientName"

if ($fwClientName -ieq $activeName)  { Write-Log "Name already correct. Nothing to do."; exit 0 }
if ($fwClientName -ieq $pendingName) { Write-Log "Rename already pending; waiting for reboot."; exit 0 }

# ================= Build rename parameters =================
$renameParams = @{ NewName = $fwClientName; Force = $true; PassThru = $true; ErrorAction = "Stop" }

if ($partOfDomain) {
    $user = $Env:user
    $pass = $Env:pass
    Write-Log "Env var 'user' present: $([bool]$user) | 'pass' present: $([bool]$pass)"
    if (-not $user -or -not $pass) { Write-Log "Domain-joined but credentials missing from environment." "ERROR"; exit 5 }

    if ($user -notmatch '\\' -and $user -notmatch '@') {
        Write-Log "Username '$user' has no domain part; using '$user@$domainName'" "WARN"
        $user = "$user@$domainName"
    }
    Write-Log "Using domain credential for: $user"

    # --- Diagnostics: can we reach a DC? ---
    try {
        $dc = & nltest.exe /dsgetdc:$domainName 2>&1 | Out-String
        Write-Log "nltest /dsgetdc: $($dc.Trim() -replace '\r?\n',' | ')"
    } catch { Write-Log "nltest failed: $_" "WARN" }
    try { Write-Log "Test-ComputerSecureChannel: $(Test-ComputerSecureChannel)" }
    catch { Write-Log "Test-ComputerSecureChannel failed: $($_.Exception.Message)" "WARN" }

    # --- Diagnostics: are the credentials valid? (diagnostic only) ---
    try {
        Add-Type -AssemblyName System.DirectoryServices.AccountManagement
        $ctx   = New-Object System.DirectoryServices.AccountManagement.PrincipalContext('Domain', $domainName)
        $valid = $ctx.ValidateCredentials($user, $pass)
        Write-Log "Credential validation against AD: $valid"
        if (-not $valid) { Write-Log "AD rejected these credentials (wrong password, locked account, or username format)." "ERROR" }
    } catch { Write-Log "Credential validation could not run: $($_.Exception.Message)" "WARN" }

    $secure = ConvertTo-SecureString $pass -AsPlainText -Force
    $renameParams.DomainCredential = New-Object System.Management.Automation.PSCredential($user, $secure)
} else {
    Write-Log "Not domain joined; performing local rename."
}

# ================= Rename =================
try {
    Write-Log "Renaming '$activeName' -> '$fwClientName'"
    $result = Rename-Computer @renameParams
    Write-Log "Rename-Computer succeeded. HasSucceeded: $($result.HasSucceeded)"

    shutdown.exe /r /t 60 /c "Computer renamed to $fwClientName. Rebooting in 60 seconds." /f /d p:4:1
    Write-Log "Reboot scheduled (shutdown.exe exit code: $LASTEXITCODE)"
    exit 2
} catch {
    $msg = $_.Exception.Message
    Write-Log "Rename-Computer FAILED: $msg" "ERROR"
    Write-Log "Exception type: $($_.Exception.GetType().FullName) | HResult: 0x{0:X}" -f $_.Exception.HResult "ERROR"
    Write-Log "Full error: $($_ | Out-String)" "ERROR"

    if ($msg -match 'denied') {
        Write-Log "HINT: Access denied. Usually the AD account lacks rights on this computer object (needs to be able to rename computer objects in that OU), or the process isn't elevated." "ERROR"
    } elseif ($msg -match 'domain controller|RPC|network path|not available') {
        Write-Log "HINT: Can't reach a DC. Check VPN/network and DNS." "ERROR"
    } elseif ($msg -match 'password|user name') {
        Write-Log "HINT: Bad credentials or username format. Try DOMAIN\user or user@domain.fqdn." "ERROR"
    }
    exit 3
}